home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
djgpp
/
demos
/
puzzle
/
main.c
< prev
next >
Wrap
Text File
|
1994-08-12
|
30KB
|
1,219 lines
/* $XConsortium: main.c,v 1.15 91/02/18 18:04:16 converse Exp $ */
/* Puzzle - (C) Copyright 1987, 1988 Don Bennett.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation.
*/
#define DEBUG
#define USE_PICTURE
#define SERVER_BUG
/** Puzzle
**
** Don Bennett, HP Labs
**
** this is the interface code for the puzzle program.
**/
#include <stdio.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "ac.cursor"
#include "ac_mask"
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define abs(x) ((x)>0?(x):-(x))
#define PUZZLE_BORDER_WIDTH 2
#define TITLE_WINDOW_HEIGHT 25
#define BOUNDARY_HEIGHT 3
#define BOX_WIDTH 10
#define BOX_HEIGHT 10
#define MIN_TILE_HEIGHT 30
#define MIN_TILE_WIDTH 30
#define MAX_STEPS 1000
#define DEFAULT_SPEED 5
#define TITLE_TILES 0
#define TITLE_TEXT 1
#define TITLE_ANIMATED 2
int BoxWidth = BOX_WIDTH;
int BoxHeight = BOX_HEIGHT;
int PuzzleSize = 4;
int PuzzleWidth=4, PuzzleHeight=4;
char defaultPuzzleSize[] = "4x4";
int TileHeight, TileWidth;
int TextXStart;
int TitleWinHeight, BoundaryHeight, TileWinHeight;
int FgPixel, BgPixel;
Display *dpy;
int screen;
GC gc, rect_gc;
Colormap PuzzleColormap;
typedef struct {
Window root;
int x,y;
unsigned int width, height;
unsigned int border_width;
unsigned int depth;
} WindowGeom;
WindowGeom PuzzleWinInfo;
Window PuzzleRoot, TitleWindow=0, TileWindow,
ScrambleWindow, SolveWindow;
char *ProgName;
char *TitleFontName = "8x13";
char *TileFontName = "8x13bold";
XFontStruct *TitleFontInfo,
*TileFontInfo;
extern int OutputLogging;
extern int *position;
extern int space_x, space_y;
int UsePicture = 0;
int UseDisplay = 0;
int CreateNewColormap = 0;
char *PictureFileName;
long PictureWidth;
long PictureHeight;
Pixmap PicturePixmap;
int TilesPerSecond;
int MoveSteps;
int VertStepSize[MAX_STEPS];
int HoriStepSize[MAX_STEPS];
#define LEFT 0
#define RIGHT 1
#define UP 2
#define DOWN 3
#define indx(x,y) (((y)*PuzzleWidth) + (x))
#define isdigit(x) ((x)>= '0' && (x) <= '9')
#define ulx(x,y) ((x)*TileWidth)
#define llx(x,y) ((x)*TileWidth)
#define urx(x,y) (((x)+1)*TileWidth - 1)
#define lrx(x,y) (((x)+1)*TileWidth - 1)
#define uly(x,y) ((y)*TileHeight)
#define ury(x,y) ((y)*TileHeight)
#define lly(x,y) (((y)+1)*TileHeight - 1)
#define lry(x,y) (((y)+1)*TileHeight - 1)
/*
* PuzzlePending - XPending entry point fo the other module.
*/
PuzzlePending()
{
return(XPending(dpy));
}
/*
* SetupDisplay - eastablish the connection to the X server.
*/
SetupDisplay(server)
char *server;
{
dpy = XOpenDisplay(server);
if (dpy == NULL) {
fprintf(stderr, "%s: unable to open display '%s'\n",
ProgName, XDisplayName (server));
exit(1);
}
screen = DefaultScreen(dpy);
#ifdef DEBUG
XSynchronize(dpy,1);
#endif /* DEBUG */
}
XQueryWindow(window,frame)
Window window;
WindowGeom *frame;
{
XGetGeometry(dpy, window,
&(frame->root),
&(frame->x), &(frame->y),
&(frame->width), &(frame->height),
&(frame->border_width),
&(frame->depth));
}
RectSet(W,x,y,w,h,pixel)
Window W;
int x,y;
unsigned int w,h;
unsigned long pixel;
{
XSetForeground(dpy, rect_gc, pixel);
XFillRectangle(dpy, W, rect_gc, x, y, w, h);
}
MoveArea(W,src_x,src_y,dst_x,dst_y,w,h)
Window W;
int src_x, src_y, dst_x, dst_y;
unsigned int w, h;
{
XCopyArea(dpy,W,W,gc,src_x,src_y,w,h,dst_x,dst_y);
}
/** RepaintTitle - puts the program title in the title bar **/
RepaintTitle(method)
int method;
{
int Twidth,Theight;
int i,j, startColor,color2,tinyBoxSize;
int Tx, Ty;
/*
* applications painting their own title is out of style,
* so don't just leave it there;
*/
tinyBoxSize = 5;
Twidth = PuzzleWinInfo.width*3/4;
Tx = (PuzzleWinInfo.width-Twidth)/2;
TextXStart = Tx;
if (method == TITLE_TEXT) {
Twidth = XTextWidth(TitleFontInfo,ProgName,strlen(ProgName));
Theight = TitleFontInfo->ascent + TitleFontInfo->descent;
Tx = (PuzzleWinInfo.width-Twidth)/2;
Ty = (TitleWinHeight-Theight)/2 + TitleFontInfo->ascent;
XSetFont(dpy, gc, TitleFontInfo->fid);
XDrawString(dpy, TitleWindow, gc,Tx, Ty, ProgName,strlen(ProgName));
XFlush(dpy);
}
else if (method == TITLE_TILES) {
for (i=0,startColor=0; i<TitleWinHeight; i+=tinyBoxSize,startColor++)
for (j=0,color2=startColor; j<Twidth; j+=tinyBoxSize,color2++)
RectSet(TitleWindow,j+TextXStart,i,tinyBoxSize,tinyBoxSize,
color2%2);
}
else {
/** method == TITLE_ANIMATED **/
unsigned char *colorVal;
int *xLoc, *yLoc, *permute;
int tilesHigh, tilesWide, numTiles, counter, swapWith, tmp;
tilesHigh = (TitleWinHeight+tinyBoxSize-1)/tinyBoxSize;
tilesWide = (Twidth+tinyBoxSize-1)/tinyBoxSize;
numTiles = tilesHigh * tilesWide;
colorVal = (unsigned char *) malloc(numTiles);
xLoc = (int *) malloc(numTiles * sizeof(int));
yLoc = (int *) malloc(numTiles * sizeof(int));
permute = (int *) malloc(numTiles * sizeof(int));
for (i=0; i<numTiles; i++)
permute[i] = i;
for (i=numTiles-1; i>1; i--) {
swapWith = rand()%i;
tmp = permute[swapWith];
permute[swapWith] = permute[i];
permute[i] = tmp;
}
counter = 0;
for (i=0,startColor=0; i<TitleWinHeight; i+=tinyBoxSize,startColor++)
for (j=0,color2=startColor; j<Twidth; j+=tinyBoxSize,color2++) {
colorVal[counter] = color2%2;
xLoc[counter] = j+TextXStart;
yLoc[counter] = i;
counter++;
}
for (i=0; i<numTiles; i++) {
j = permute[i];
RectSet(TitleWindow,xLoc[j],yLoc[j],tinyBoxSize,tinyBoxSize,
colorVal[j]);
XFlush(dpy);
}
free(colorVal);
free(xLoc);
free(yLoc);
free(permute);
}
}
/*
* RepaintBar - Repaint the bar between the title window and
* the tile window;
*/
RepaintBar()
{
XFillRectangle(dpy, PuzzleRoot, gc,
0, TitleWinHeight,
PuzzleWinInfo.width, BoundaryHeight);
}
/**
** RepaintTiles - draw the numbers in the tiles to match the
** locations array;
**/
RepaintTiles()
{
#ifdef USE_PICTURE
if (UsePicture)
RepaintPictureTiles();
else
#endif /* USE_PICTURE */
RepaintNumberTiles();
}
RepaintNumberTiles()
{
int i,j,counter;
int width,height;
int x_offset,y_offset;
char str[30];
/** cut the TileWindow into a grid of nxn pieces by inscribing
** each rectangle with a black border;
** I don't want to use subwindows for each tile so that I can
** slide groups of tiles together as a single unit, rather than
** being forced to move one tile at a time.
**/
#define line(x1,y1,x2,y2) XDrawLine(dpy,TileWindow,gc,(x1),(y1),(x2),(y2))
#define rect(x,y) (line(ulx(x,y),uly(x,y),urx(x,y),ury(x,y)), \
line(urx(x,y),ury(x,y),lrx(x,y),lry(x,y)), \
line(lrx(x,y),lry(x,y),llx(x,y),lly(x,y)), \
line(llx(x,y),lly(x,y),ulx(x,y),uly(x,y)))
height = TileFontInfo->ascent + TileFontInfo->descent;
y_offset = (TileHeight - height)/2 + TileFontInfo->ascent;
XSetFont(dpy, gc, TileFontInfo->fid);
counter = 0;
for (i=0; i<PuzzleHeight; i++)
for (j=0; j<PuzzleWidth; j++) {
if (position[counter] == 0) {
RectSet(TileWindow,ulx(j,i),uly(j,i),
TileWidth,TileHeight,FgPixel);
}
else {
RectSet(TileWindow,ulx(j,i),uly(j,i),TileWidth,TileHeight,
BgPixel);
rect(j,i);
sprintf(str,"%d",position[counter]);
width = XTextWidth(TileFontInfo,str,strlen(str));
x_offset = (TileWidth - width)/2;
XDrawString(dpy, TileWindow, gc,
ulx(j,i)+x_offset,uly(j,i)+y_offset,
str,strlen(str));
}
counter++;
}
}
#ifdef USE_PICTURE
RepaintPictureTiles()
{
int i, j, counter;
int tmp, orig_x,orig_y;
counter = 0;
for (i=0; i<PuzzleHeight; i++)
for (j=0; j<PuzzleWidth; j++) {
if (position[counter] == 0)
RectSet(TileWindow,ulx(j,i),uly(j,i),
TileWidth,TileHeight,FgPixel);
else {
tmp = position[counter] - 1;
orig_x = tmp % PuzzleWidth;
orig_y = tmp / PuzzleWidth;
XCopyArea(dpy,PicturePixmap,TileWindow,gc,
ulx(orig_x,orig_y), uly(orig_x,orig_y),
TileWidth, TileHeight,
ulx(j,i), uly(j,i));
}
counter++;
}
}
#endif /* USE_PICTURE */
/**
** Setup - Perform initial window creation, etc.
**/
Setup (geom,argc,argv)
char *geom;
int argc;
char *argv[];
{
int minwidth, minheight;
Pixmap PictureSetup();
Visual visual;
XGCValues xgcv;
XSetWindowAttributes xswa;
XSizeHints sizehints;
/*******************************************/
/** let the puzzle code initialize itself **/
/*******************************************/
initialize();
OutputLogging = 1;
FgPixel = BlackPixel(dpy,screen);
BgPixel = WhitePixel(dpy,screen);
TitleWinHeight = TITLE_WINDOW_HEIGHT;
BoundaryHeight = BOUNDARY_HEIGHT;
#ifdef USE_PICTURE
/*****************************************************/
/** if we want to use a picture file, initialize it **/
/*****************************************************/
if (UsePicture) {
/**
** This was fun to do back with X10 when you could create
** a pixmap from the current display contents; No more, I guess.
**/
#ifdef UNDEFINED
if (UseDisplay) {
WindowGeom RootWinInfo;
int x,y;
x = PUZZLE_BORDER_WIDTH;
y = TITLE_WINDOW_HEIGHT + BOUNDARY_HEIGHT + PUZZLE_BORDER_WIDTH;
XQueryWindow(RootWindow(dpy, screen),&RootWinInfo);
PictureWidth = RootWinInfo.width - x;
PictureHeight = RootWinInfo.height - y;
PicturePixmap = XPixmapSave(RootWindow(dpy,screen),
x,y,PictureWidth,PictureHeight);
}
else
#endif /* UNDEFINED */
PicturePixmap = PictureSetup(PictureFileName,&PictureWidth,
&PictureHeight);
}
#endif /* USE_PICTURE */
#ifdef USE_PICTURE
if (UsePicture) {
minwidth = PictureWidth;
minheight = PictureHeight + TITLE_WINDOW_HEIGHT + BOUNDARY_HEIGHT;
}
else {
#endif /* USE_PICTURE */
minwidth = MIN_TILE_WIDTH * PuzzleWidth;
minheight = MIN_TILE_HEIGHT * PuzzleHeight + TITLE_WINDOW_HEIGHT +
BOUNDARY_HEIGHT;
#ifdef USE_PICTURE
}
#endif /* USE_PICTURE */
/*************************************/
/** configure the window size hints **/
/*************************************/
{
int x, y, width, height;
int tileHeight, tileWidth;
int flags;
sizehints.flags = PMinSize | PPosition | PSize | PResizeInc;
sizehints.min_width = minwidth;
sizehints.min_height = minheight;
sizehints.width = minwidth;
sizehints.height = minheight;
sizehints.x = 100;
sizehints.y = 300;
sizehints.width_inc = PuzzleWidth;
sizehints.height_inc = PuzzleHeight;
#ifdef USE_PICTURE
if (UsePicture) {
sizehints.flags |= PMaxSize;
sizehints.max_width = sizehints.min_width;
sizehints.max_height = sizehints.min_height;
}
#endif /* USE_PICTURE */
if(strlen(geom)) {
flags = XParseGeometry(geom, &x, &y,
(unsigned int *)&width,
(unsigned int *)&height);
if(WidthValue & flags) {
sizehints.flags |= USSize;
if (width > sizehints.min_width)
sizehints.width = width;
}
if(HeightValue & flags) {
sizehints.flags |= USSize;
if (height > sizehints.min_height)
sizehints.height = height;
}
if(XValue & flags) {
if(XNegative & flags)
x = DisplayWidth(dpy, DefaultScreen(dpy)) + x
- sizehints.width;
sizehints.flags |= USPosition;
sizehints.x = x;
}
if(YValue & flags) {
if(YNegative & flags)
y = DisplayHeight(dpy, DefaultScreen(dpy)) + y
-sizehints.height;
sizehints.flags |= USPosition;
sizehints.y = y;
}
tileHeight = (sizehints.height-TitleWinHeight-BoundaryHeight)/PuzzleHeight;
sizehints.height = tileHeight*PuzzleHeight+TitleWinHeight+BoundaryHeight;
tileWidth = sizehints.width/PuzzleWidth;
sizehints.width = tileWidth * PuzzleWidth;
}
}
/*******************************************************************/
/** create the puzzle main window and set its standard properties **/
/*******************************************************************/
xswa.event_mask = ExposureMask;
visual.visualid = CopyFromParent;
PuzzleRoot = XCreateSimpleWindow(dpy, RootWindow(dpy,screen),
sizehints.x, sizehints.y,
sizehints.width, sizehints.height,
PUZZLE_BORDER_WIDTH, FgPixel,FgPixel);
XSetStandardProperties(dpy, PuzzleRoot,"puzzle","Puzzle",
None, argv, argc, &sizehints);
if (CreateNewColormap)
XSetWindowColormap(dpy, PuzzleRoot, PuzzleColormap);
xgcv.foreground = FgPixel;
xgcv.background = BgPixel;
xgcv.line_width = 1;
gc = XCreateGC(dpy, PuzzleRoot,
GCForeground|GCBackground|GCLineWidth,
&xgcv);
/*********************************/
/** load the arrow-cross cursor **/
/*********************************/
{
Pixmap ACPixmap, ACMask;
Cursor ACCursor;
XColor FGcolor, BGcolor;
FGcolor.red = 0; FGcolor.green = 0; FGcolor.blue = 0;
BGcolor.red = 0xffff; BGcolor.green = 0xffff; BGcolor.blue = 0xffff;
ACPixmap = XCreateBitmapFromData(dpy,RootWindow(dpy,screen),
(char *) ac_bits,
ac_width, ac_height);
ACMask = XCreateBitmapFromData(dpy,RootWindow(dpy,screen),
(char *) ac_mask_bits,
ac_mask_width, ac_mask_height);
ACCursor = XCreatePixmapCursor(dpy,ACPixmap,ACMask,
&FGcolor,&BGcolor,
ac_x_hot, ac_y_hot);
if (ACCursor == (Cursor)NULL)
error("Unable to store ArrowCrossCursor.");
XDefineCursor(dpy,PuzzleRoot,ACCursor);
}
/*****************************************/
/** allocate the fonts we will be using **/
/*****************************************/
TitleFontInfo = XLoadQueryFont(dpy,TitleFontName);
TileFontInfo = XLoadQueryFont(dpy,TileFontName);
if (TitleFontInfo == NULL) error("Opening title font.\n");
if (TileFontInfo == NULL) error("Opening tile font.\n");
XSelectInput(dpy, PuzzleRoot, ExposureMask|VisibilityChangeMask);
XMapWindow(dpy,PuzzleRoot);
}
static short old_height = -1;
static short old_width = -1;
SizeChanged()
{
XQueryWindow(PuzzleRoot,&PuzzleWinInfo);
if (PuzzleWinInfo.width == old_width &&
PuzzleWinInfo.height == old_height)
return(0);
else
return(1);
}
Reset()
{
int Box_x,Box_y;
int TileBgPixel;
/** TileWindow is that portion of PuzzleRoot that contains
** the sliding pieces;
**/
if (UsePicture)
TileBgPixel = BlackPixel(dpy,screen);
else
TileBgPixel = WhitePixel(dpy,screen);
#ifdef SERVER_BUG
/* seems I need to do this, or the next title window will be obscured
* by the old title window! This must be a server bug, right?
*/
if (TitleWindow) XUnmapWindow(dpy,TitleWindow);
/* if (TitleWindow) XDestroyWindow(dpy,TitleWindow); */
#endif /* SERVER_BUG */
XDestroySubwindows(dpy,PuzzleRoot);
/** fix the dimensions of PuzzleRoot so the height and width
** of the TileWindow will work out to be multiples of PuzzleSize;
**/
/** If we're dealing with a picture, the tile region can be no larger
** than the picture!
**/
#ifdef USE_PICTURE
if (UsePicture) {
int tmp;
tmp = PuzzleWinInfo.height - TitleWinHeight - BoundaryHeight;
if (tmp > PictureHeight)
PuzzleWinInfo.height = PictureHeight+TitleWinHeight+BoundaryHeight;
if (PuzzleWinInfo.width > PictureWidth)
PuzzleWinInfo.width = PictureWidth;
}
#endif /* USE_PICTURE */
TileHeight=(PuzzleWinInfo.height-TitleWinHeight-BoundaryHeight)/PuzzleHeight;
/* PuzzleWinInfo.height = TileHeight*PuzzleHeight+TitleWinHeight+BoundaryHeight; */
TileWidth = PuzzleWinInfo.width/PuzzleWidth;
/* PuzzleWinInfo.width = TileWidth * PuzzleWidth; */
/** fixup the size of PuzzleRoot **/
/* XResizeWindow(dpy,PuzzleRoot,PuzzleWinInfo.width,PuzzleWinInfo.height); */
old_width = PuzzleWinInfo.width;
old_height = PuzzleWinInfo.height;
TileWinHeight = PuzzleWinInfo.height - TitleWinHeight;
TitleWindow = XCreateSimpleWindow(dpy, PuzzleRoot,
0,0,
PuzzleWinInfo.width, TitleWinHeight,
0,0,BgPixel);
TileWindow = XCreateSimpleWindow(dpy, PuzzleRoot,
0,TitleWinHeight+BoundaryHeight,
PuzzleWinInfo.width, TileWinHeight,
0,0,TileBgPixel);
rect_gc = XCreateGC(dpy,TileWindow,0,0);
XCopyGC(dpy, gc, -1, rect_gc);
XMapWindow(dpy,TitleWindow);
XMapWindow(dpy,TileWindow);
XSync(dpy,0);
RepaintBar();
RepaintTitle(TITLE_TEXT);
/** locate the two check boxes **/
Box_x = TextXStart/2 - BoxWidth/2;
Box_y = TitleWinHeight/2 - BoxHeight/2;
ScrambleWindow = XCreateSimpleWindow(dpy, TitleWindow,
Box_x, Box_y,
BoxWidth, BoxHeight,
1,FgPixel,BgPixel);
Box_x = PuzzleWinInfo.width - Box_x - BoxWidth;
SolveWindow = XCreateSimpleWindow(dpy, TitleWindow,
Box_x,Box_y,
BoxWidth,BoxHeight,
1,FgPixel,BgPixel);
XMapWindow(dpy,ScrambleWindow);
XMapWindow(dpy,SolveWindow);
XSync(dpy,0);
XSelectInput(dpy, TitleWindow, ButtonPressMask|ExposureMask);
XSelectInput(dpy, TileWindow, ButtonPressMask|ExposureMask|
VisibilityChangeMask);
XSelectInput(dpy, ScrambleWindow,ButtonPressMask|ExposureMask);
XSelectInput(dpy, SolveWindow, ButtonPressMask|ExposureMask);
RepaintTiles();
RepaintTitle(TITLE_ANIMATED);
CalculateSpeed();
CalculateStepsize();
XSync(dpy,0);
}
/*
* Sets the global variable MoveSteps based on speed
* specified on the command line;
*/
#if defined(USG) && !defined(Cray) /* tv_usec never changes */
#define MIN_DELTA_T 100L
#else /* don't divide by zero */
#define MIN_DELTA_T 1L
#endif
/** delta-t in miliseconds **/
#define DeltaT(tv2,tv1) \
( ((tv2.tv_sec - tv1.tv_sec )*1000L) \
+((tv2.tv_usec - tv1.tv_usec)/1000L))
CalculateSpeed()
{
struct timeval tv1, tv2;
struct timezone tz;
int i, x, y;
long timePerTile;
static int firstCall = 1;
long delta;
if (!firstCall)
return;
firstCall = 0;
x = space_x * TileWidth;
y = space_y * TileHeight;
timePerTile = (long)(1000/TilesPerSecond);
XSync(dpy,0);
gettimeofday(&tv1, &tz);
tv2 = tv1;
MoveSteps = 0;
delta = 0L;
while (delta < timePerTile) {
MoveArea(TileWindow,x,y,x+1,y,TileWidth,TileHeight);
RectSet(TileWindow,x,y,1,TileHeight,FgPixel);
XSync(dpy,0);
gettimeofday(&tv2, &tz);
delta = DeltaT(tv2,tv1);
delta = max(MIN_DELTA_T, delta);
if (delta >= 0) MoveSteps++; /* crock for broken systems */
}
/*
* now, see how long this takes without all the extra b.s.
* and compensate;
*/
XSync(dpy,0);
gettimeofday(&tv1, &tz);
for (i=0; i<MoveSteps; i++) {
MoveArea(TileWindow,x,y,x+1,y,TileWidth,TileHeight);
RectSet(TileWindow,x,y,1,TileHeight,FgPixel);
}
XFlush(dpy);
gettimeofday(&tv2, &tz);
delta = DeltaT(tv2, tv1);
delta = max(MIN_DELTA_T, delta);
MoveSteps = (((long)MoveSteps) * timePerTile)/(delta ? delta : 1L);
if (MoveSteps <= 0)
MoveSteps = 1;
}
CalculateStepsize()
{
int i, rem;
int error,sum;
for (i=0; i<MoveSteps; i++)
VertStepSize[i] = TileHeight/MoveSteps;
rem = TileHeight % MoveSteps;
error = - MoveSteps/2;
if (rem > 0)
for (i=0; i<MoveSteps; i++) {
if (error >= 0) {
VertStepSize[i]++;
error -= MoveSteps;
}
error += rem;
}
for (i=0; i<MoveSteps; i++)
HoriStepSize[i] = TileWidth/MoveSteps;
rem = TileWidth % MoveSteps;
error = - MoveSteps/2;
if (rem > 0)
for (i=0; i<MoveSteps; i++) {
if (error >= 0) {
HoriStepSize[i]++;
error -= MoveSteps;
}
error += rem;
}
/** This code is a little screwed up and I don't want to fix it
** right now, so just do a little hack to make sure the total
** distance comes out right;
**/
sum = 0;
for (i=0; i<MoveSteps; i++)
sum += HoriStepSize[i];
HoriStepSize[0] += TileWidth - sum;
sum = 0;
for (i=0; i<MoveSteps; i++)
sum += VertStepSize[i];
VertStepSize[0] += TileHeight - sum;
}
SlidePieces(event)
XButtonEvent *event;
{
int x,y;
x = (*event).x / TileWidth;
y = (*event).y / TileHeight;
if (x == space_x || y == space_y)
move_space_to(indx(x,y));
flushLogging();
}
ProcessVisibility(event)
XVisibilityEvent *event;
{
if (event->state != VisibilityUnobscured) AbortSolving();
}
ProcessExpose(event)
XExposeEvent *event;
{
int loop = 1;
int reset = 0,
title = 0,
tiles = 0,
bar = 0;
loop = 1;
while (loop) {
if (event->count == 0) {
if (event->window == TitleWindow)
title++;
else if (event->window == TileWindow)
tiles++;
else if (event->window == PuzzleRoot)
bar++;
}
loop = XCheckMaskEvent(dpy, ExposureMask, (XEvent *)event);
}
if (SizeChanged())
reset++;
if (reset)
Reset();
else {
if (title) RepaintTitle(TITLE_TILES);
if (tiles) RepaintTiles();
if (bar) RepaintBar();
}
}
ProcessButton(event)
XButtonEvent *event;
{
Window w;
w = event->window;
if (w == TileWindow) {
if (SolvingStatus())
AbortSolving();
else
SlidePieces(event);
}
else if (w == ScrambleWindow) {
AbortSolving();
Scramble();
RepaintTiles();
}
else if (w == SolveWindow)
Solve();
else if ((w == TitleWindow) && (*event).button == Button2)
exit(0);
}
ProcessInput()
{
XEvent event;
while(1) {
GetNextEvent(&event);
ProcessEvent(&event);
}
}
ProcessEvents()
{
XEvent event;
while(XPending(dpy)) {
GetNextEvent(&event);
ProcessEvent(&event);
}
}
GetNextEvent(event)
XEvent *event;
{
if (!XCheckMaskEvent(dpy,VisibilityChangeMask,event) &&
!XCheckMaskEvent(dpy,ExposureMask,event))
XNextEvent(dpy,event);
}
ProcessEvent(event)
XEvent *event;
{
switch(event->type) {
case ButtonPress:
ProcessButton(&event->xbutton);
break;
case Expose:
ProcessExpose(&event->xexpose);
break;
case VisibilityNotify:
ProcessVisibility(&event->xvisibility);
break;
default:
break;
}
}
main(argc,argv)
int argc;
char *argv[];
{
int i;
char *ServerName, *Geometry;
char *puzzle_size = NULL;
char *option;
ProgName = argv[0];
ServerName = "";
Geometry = "";
TilesPerSecond = -1;
/********************************/
/** parse command line options **/
/********************************/
for (i=1; i<argc; i++) {
char *arg = argv[i];
if (arg[0] == '-') {
switch (arg[1]) {
case 'd': /* -display host:dpy */
if (++i >= argc) usage ();
ServerName = argv[i];
continue;
case 'g': /* -geometry geom */
if (++i >= argc) usage ();
Geometry = argv[i];
continue;
case 's': /* -size WxH or -speed n */
if (arg[2] == 'i') {
if (++i >= argc) usage ();
puzzle_size = argv[i];
continue;
} else if (arg[2] == 'p') {
if (++i >= argc) usage ();
TilesPerSecond = atoi (argv[i]);
continue;
} else
usage ();
break;
case 'p': /* -picture filename */
if (++i >= argc) usage ();
UsePicture++;
PictureFileName = argv[i];
continue;
case 'c': /* -colormap */
CreateNewColormap++;
continue;
default:
usage ();
} /* end switch */
} else
usage ();
} /* end for */
SetupDisplay (ServerName);
if (!Geometry) {
Geometry = XGetDefault (dpy, ProgName, "Geometry");
}
if (!puzzle_size) {
option = XGetDefault (dpy, ProgName, "Size");
puzzle_size = option ? option : defaultPuzzleSize;
}
if (TilesPerSecond <= 0) {
option = XGetDefault (dpy, ProgName, "Speed");
TilesPerSecond = option ? atoi (option) : DEFAULT_SPEED;
}
if (!UsePicture) {
option = XGetDefault (dpy, ProgName, "Picture");
if (option) {
UsePicture++;
PictureFileName = option;
}
}
if (!CreateNewColormap) {
option = XGetDefault (dpy, ProgName, "Colormap");
if (option) {
CreateNewColormap++;
}
}
sscanf (puzzle_size, "%dx%d", &PuzzleWidth, &PuzzleHeight);
if (PuzzleWidth < 4 || PuzzleHeight < 4) {
fprintf (stderr, "%s: Puzzle size must be at least 4x4\n",
ProgName);
exit (1);
}
PuzzleSize = min((PuzzleWidth/2)*2,(PuzzleHeight/2)*2);
Setup (Geometry,argc,argv);
ProcessInput();
exit (0);
}
static char *help_message[] = {
"where options include:",
" -display host:dpy X server to use",
" -geometry geom geometry of puzzle window",
" -size WxH number of squares in puzzle",
" -speed number tiles to move per second",
" -picture filename image to use for tiles",
" -colormap create a new colormap",
NULL};
usage()
{
char **cpp;
fprintf (stderr, "usage: %s [-options ...]\n\n", ProgName);
for (cpp = help_message; *cpp; cpp++) {
fprintf (stderr, "%s\n", *cpp);
}
fprintf (stderr, "\n");
exit (1);
}
error(str)
char *str;
{
fprintf(stderr,"Error %s\n",str);
exit(1);
}
/**
** Output Routines -
**/
resetLogging()
{ }
flushLogging()
{ }
saveLoggingState()
{ }
LogMoveSpace(first_x,first_y,last_x,last_y,dir)
int first_x,first_y,last_x,last_y,dir;
{
displayLogMoveSpace(first_x,first_y,last_x,last_y,dir);
}
#ifdef UNDEFINED
/** this stuff really isn't worth it; **/
static int prevDir = -1;
static int prevFirstX, prevFirstY, prevLastX, prevLastY;
resetLogging()
{
prevDir = -1;
}
flushLogging()
{
if (prevDir != -1)
displayLogMoveSpace(prevFirstX,prevFirstY,prevLastX,prevLastY,prevDir);
prevDir = -1;
}
saveLoggingState(fx,fy,lx,ly,dir)
int fx,fy,lx,ly,dir;
{
prevDir = dir;
prevFirstX = fx;
prevFirstY = fy;
prevLastX = lx;
prevLastY = ly;
}
LogMoveSpace(first_x,first_y,last_x,last_y,dir)
int first_x,first_y,last_x,last_y,dir;
{
if (prevDir == -1)
/** we don't already have something to move **/
saveLoggingState(first_x,first_y,last_x,last_y,dir);
else if (prevDir == dir) {
/** we're going in the same direction **/
prevLastX = last_x;
prevLastY = last_y;
}
else {
flushLogging();
saveLoggingState(first_x,first_y,last_x,last_y,dir);
}
}
#endif /* UNDEFINED */
displayLogMoveSpace(first_x,first_y,last_x,last_y,dir)
int first_x,first_y,last_x,last_y,dir;
{
int min_x,min_y,max_x,max_y;
int x,y,w,h,dx,dy,x2,y2;
int i, clear_x, clear_y;
max_x = max(first_x,last_x);
min_x = min(first_x,last_x);
max_y = max(first_y,last_y);
min_y = min(first_y,last_y);
x = ulx(min_x,0);
y = uly(0,min_y);
w = (max_x - min_x + 1)*TileWidth;
h = (max_y - min_y + 1)*TileHeight;
dx = x;
dy = y;
x2 = x;
y2 = y;
switch(dir) {
case UP: clear_x = llx(max_x,0);
clear_y = lly(0,max_y) + 1;
for (i=0; i<MoveSteps; i++) {
dy = VertStepSize[i];
y2 = y - dy;
clear_y -= dy;
MoveArea(TileWindow,x,y,x2,y2,w,h);
RectSet(TileWindow,clear_x,clear_y,
TileWidth,dy,FgPixel);
y -= dy;
}
break;
case DOWN: clear_x = llx(max_x,0);
clear_y = uly(0,min_y);
for (i=0; i<MoveSteps; i++) {
dy = VertStepSize[i];
y2 = y + dy;
MoveArea(TileWindow,x,y,x2,y2,w,h);
RectSet(TileWindow,clear_x,clear_y,
TileWidth,dy,FgPixel);
y += dy;
clear_y += dy;
}
break;
case LEFT: clear_x = urx(max_x,0) + 1;
clear_y = ury(0,max_y);
for (i=0; i<MoveSteps; i++) {
dx = HoriStepSize[i];
x2 = x - dx;
clear_x -= dx;
MoveArea(TileWindow,x,y,x2,y2,w,h);
RectSet(TileWindow,clear_x,clear_y,
dx,TileHeight,FgPixel);
x -= dx;
}
break;
case RIGHT: clear_x = ulx(min_x,0);
clear_y = uly(0,max_y);
for (i=0; i<MoveSteps; i++) {
dx = HoriStepSize[i];
x2 = x + dx;
MoveArea(TileWindow,x,y,x2,y2,w,h);
RectSet(TileWindow,clear_x,clear_y,
dx,TileHeight,FgPixel);
x += dx;
clear_x += dx;
}
break;
}
XFlush(dpy);
}